package vn.edu.saigontech.ncms.model.info;

import java.text.Collator;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.OrderBy;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

import org.hibernate.annotations.OptimisticLockType;

import vn.edu.saigontech.ncms.model.BaseEntity;
import vn.edu.saigontech.ncms.model.enumeration.AttendanceStatus;
import vn.edu.saigontech.ncms.model.enumeration.TeachingInterruptionReason;
import vn.edu.saigontech.ncms.model.program.Level;
import vn.edu.saigontech.ncms.model.result.FinalTest;
import vn.edu.saigontech.ncms.model.result.GradeDetail;
import vn.edu.saigontech.ncms.model.result.SecondTest;
import vn.edu.saigontech.ncms.model.studying.AbsenceRecord;
import vn.edu.saigontech.ncms.model.studying.Attendance;
import vn.edu.saigontech.ncms.model.studying.ClassSituation;
import vn.edu.saigontech.ncms.model.studying.EvaluateTeacher;
import vn.edu.saigontech.ncms.model.studying.Opinion;
import vn.edu.saigontech.ncms.model.studying.Suggestion;
import vn.edu.saigontech.ncms.model.system.Room;
import vn.edu.saigontech.ncms.model.system.Shift;
import vn.edu.saigontech.ncms.model.teaching.OfferingChecking;
import vn.edu.saigontech.ncms.model.teaching.TeachingInterruption;
import vn.edu.saigontech.ncms.model.teaching.TeachingSwitch;
import vn.edu.saigontech.ncms.model.teaching.TestSchedule;
import vn.edu.saigontech.ncms.model.teaching.VideoSchedule;
import vn.edu.saigontech.ncms.util.Checker;
import vn.edu.saigontech.ncms.util.DateUtil;

@Entity
@org.hibernate.annotations.Entity(dynamicInsert = true, dynamicUpdate = true, optimisticLock = OptimisticLockType.ALL)
@Table(name = "ncms_offering")
@SuppressWarnings("serial")
public class Offering extends BaseEntity {

	@Column(name = "name", nullable = false)
	private String name;

	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "level_id", nullable = false)
	private Level level;

	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "room_id")
	private Room room;

	@ManyToOne(fetch = FetchType.EAGER)
	@JoinColumn(name = "shift_id")
	private Shift shift;

	@Temporal(TemporalType.DATE)
	@Column(name = "start_date")
	private Date startDate;

	@Temporal(TemporalType.DATE)
	@Column(name = "end_date")
	private Date endDate;

	@Temporal(TemporalType.DATE)
	@Column(name = "midterm_written_date")
	private Date midtermWrittenDate;

	@Temporal(TemporalType.DATE)
	@Column(name = "final_spoken_date")
	private Date finalSpokenDate;

	@Temporal(TemporalType.DATE)
	@Column(name = "final_written_date")
	private Date finalWrittenDate;
	
	@Temporal(TemporalType.DATE)
	@Column(name = "cambridge_spoken_date")	
	private Date cambridgeSpokenDate;
	
	@Temporal(TemporalType.DATE)
	@Column(name = "cambridge_written_date")
	private Date cambridgeWrittenDate; 

	@Temporal(TemporalType.DATE)
	@Column(name = "issue_date")
	private Date issueDate;

	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "mon_teacher")
	private Teacher monTeacher;
	
	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "mon_ta_teacher")
	private Teacher monTATeacher;

	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "tue_teacher_id")
	private Teacher tueTeacher;
	
	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "tue_ta_teacher_id")
	private Teacher tueTATeacher;
	
	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "web_teacher_id")
	private Teacher wedTeacher;
	
	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "web_ta_teacher_id")
	private Teacher wedTATeacher;

	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "thu_teacher_id")
	private Teacher thuTeacher;
	
	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "thu_ta_teacher_id")
	private Teacher thuTATeacher;

	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "fri_teacher_id")
	private Teacher friTeacher;
	
	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "fri_ta_teacher_id")
	private Teacher friTATeacher;

	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "sat_teacher_id")
	private Teacher satTeacher;
	
	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "sat_ta_teacher_id")
	private Teacher satTATeacher;

	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "sun_teacher_id")
	private Teacher sunTeacher;
	
	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "sun_ta_teacher_id")
	private Teacher sunTATeacher;

	@Column(name = "comment", length = 4000)
	private String comment;
	
	@Column(name = "cancel", columnDefinition="boolean default false")
	private boolean cancel;
	
	@OneToOne
	@JoinColumn(name = "midterm_grade_detail_id")
	private GradeDetail midtermGradeDetail;
	
	@OneToOne
	@JoinColumn(name = "final_grade_detail_id")
	private GradeDetail finalGradeDetail;
	
	@OneToOne
	@JoinColumn(name = "cambridge_grade_detail_id")
	private GradeDetail cambridgeGradeDetail;
	
	@ManyToOne
	@JoinColumn(name = "next_offering")
	private NextOffering nextOffering;

	@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "offering")
	@org.hibernate.annotations.Cascade(value = org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
	private Set<AbstractReceipt> offeringReceipts = new HashSet<AbstractReceipt>();

	@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "offering")
	@org.hibernate.annotations.Cascade(value = org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
	@OrderBy("id asc")
	private Set<EvaluateTeacher> evaluateTeachers = new HashSet<EvaluateTeacher>();

	@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "offering")
	@org.hibernate.annotations.Cascade(value = org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
	@OrderBy("id asc")
	private Set<Opinion> opinions = new HashSet<Opinion>();

	@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "offering")
	@org.hibernate.annotations.Cascade(value = org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
	@OrderBy("id asc")
	private Set<Suggestion> suggestions = new HashSet<Suggestion>();
	
	@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "offering")
	@org.hibernate.annotations.Cascade(value = org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
	@OrderBy("id asc")
	private Set<ClassSituation> classSituations = new HashSet<ClassSituation>();
	
	@OneToMany(cascade = CascadeType.ALL, mappedBy = "offering")
	@org.hibernate.annotations.Cascade(value = org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
	@OrderBy("offeringMember, contactingDate")
	private Set<AbsenceRecord> absences = new HashSet<AbsenceRecord>();

	@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "offering")
	@org.hibernate.annotations.Cascade(value = org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
	@OrderBy("date asc")
	private Set<OfferingChecking> offeringCheckings = new HashSet<OfferingChecking>();

	@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "offering")
	@org.hibernate.annotations.Cascade(value = org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
	@OrderBy("fromDate asc")
	private Set<TeachingInterruption> teachingInterruptions = new HashSet<TeachingInterruption>();
	
	@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "offering")
	@org.hibernate.annotations.Cascade(value = org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
	@OrderBy("fromDate asc")
	private Set<TeachingSwitch> teachingSwitchs = new HashSet<TeachingSwitch>();

	@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "offering")
	@org.hibernate.annotations.Cascade(value = org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
	@OrderBy("date asc")
	private Set<VideoSchedule> videoSchedules = new HashSet<VideoSchedule>();

	@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "offering")
	@org.hibernate.annotations.Cascade(value = org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
	@OrderBy("date asc")
	private Set<TestSchedule> testSchedules = new HashSet<TestSchedule>();
	
	public String getDisplayTimeName() {
		return DateUtil.toString(this.startDate) + "-" + DateUtil.toString(this.endDate) + " # " + this.name;
	}
	
	/**
	 * Ok
	 * get all offering members of the class
	 * @return
	 */
	public Set<OfferingMember> getMembers() {
		Set<OfferingMember> members = new HashSet<OfferingMember>();
		for (AbstractReceipt receipt : this.offeringReceipts) {
			if (receipt.getMember() != null) {
				members.add(receipt.getMember());
			}
		}
		return members;
	}
	
	public List<OfferingMember> getSortMembers() {
		List<OfferingMember> members = new ArrayList<OfferingMember>();
		for (AbstractReceipt receipt : this.offeringReceipts) {
			if (receipt.getMember() != null) {
				members.add(receipt.getMember());
			}
		}
		Collections.sort(members, new Comparator<OfferingMember>(){

			@Override
			public int compare(OfferingMember o1, OfferingMember o2) {
				int result = Collator.getInstance(new Locale("vi", "VN")).compare(o1.getReceipt().getStudent().getFirstName(), o2.getReceipt().getStudent().getFirstName());
				return result;
			}});
		return members;
	}
	
	public List<OfferingMember> getSortActiveMembers() {
		List<OfferingMember> members = new ArrayList<OfferingMember>();
		for (AbstractReceipt receipt : this.offeringReceipts) {
			if (receipt.getMember() != null && receipt.isActive()) {
				members.add(receipt.getMember());
			}
		}
		Collections.sort(members, new Comparator<OfferingMember>(){
			@Override
			public int compare(OfferingMember o1, OfferingMember o2) {
				int result = 0;
				result = Collator.getInstance(new Locale("vi", "VN")).compare(
						o1.getReceipt().getStudent().getFirstName(), 
						o2.getReceipt().getStudent().getFirstName());
				if (result != 0) return result;
				else {
					result = Collator.getInstance(new Locale("vi", "VN")).compare(
						o1.getReceipt().getStudent().getLastName(), 
						o2.getReceipt().getStudent().getLastName());
				}
				return result;
			}});
		return members;
	}

	/**
	 * Ok
	 * get all active offering members of the class
	 * @return
	 */
	public Collection<Student> getActiveStudents() {
		Collection<Student> members = new ArrayList<Student>();
		
		for (AbstractReceipt receipt : this.offeringReceipts) {
			OfferingMember member = receipt.getOfferingMember();
			Student student = receipt.getStudent();
			if (member == null || !member.isActive())
				continue;
			if (!members.contains(student))
				members.add(student);
		}
		return members;
	}

	/**
	 * Ok
	 * get all active offering members of the class
	 * @return
	 */
	public Set<OfferingMember> getActiveMembers() {
		Set<OfferingMember> members = new HashSet<OfferingMember>();
		
		for (AbstractReceipt receipt : this.offeringReceipts) {
			OfferingMember member = receipt.getOfferingMember();
			if (member != null && !members.contains(member))
				members.add(member);
		}
		return members;
	}
	
	/**
	 * Ok
	 * get all active offering members of the class
	 * @return
	 */
	public Set<OfferingMember> getInactiveMembers() {
		Set<OfferingMember> members = new HashSet<OfferingMember>();
		for (AbstractReceipt receipt : this.offeringReceipts) {
			if (receipt.getMember() != null && !receipt.isActive())
				members.add(receipt.getMember());
		}
		return members;
	}

	/**
	 * Ok
	 * count the number of students in the class
	 * @return
	 */
	public int getNumberOfStudents() {
		return this.getMembers().size();
	}

	/**
	 * Ok
	 * count the number of active students in the class
	 * @return
	 */
	public int getNumberOfActiveStudents() {
		return this.getActiveMembers().size();
	}

	public int getFreeStudents() {
		int count = 0;
		for (OfferingMember each : this.getMembers())
			if (each.getReceipt().getFee().getAmount() == 0)
				count++;
		return count;
	}
	
	public Collection<OfferingMember> getListFreeStudents() {
		Collection<OfferingMember> students = new ArrayList<OfferingMember>();
		for (OfferingMember each : this.getMembers())
			if (each.getReceipt().getFee().getAmount() == 0)
				students.add(each);
		return students;
	}
	
	/**
	 * Ok
	 * count the number of active students at a specific date
	 * @param date
	 * @return
	 */
	public int getNumberOfActiveStudents(Date date) {
		Set<Integer> teachingDays = getDays();
		if (teachingDays.isEmpty()) {
			return this.getNumberOfActiveStudents();
		}
		Integer lastDay = new LinkedList<Integer>(teachingDays).getLast();
		while (DateUtil.getDayOfWeek(date) != lastDay) {
			date = DateUtil.addDay(date, -1);
		}
		return this.getActiveMembers().size()
				- this.getNumberOfAbsentMembers(date);
	}
	
	/**
	 * Ok - halnt
	 * check whether the teacher has taught this class or not, 
	 * even when he/she either substituted or transfered
	 * @param teacher
	 * @return
	 */
	public boolean containsInstructorEven(Teacher teacher, Date fromDate, Date toDate) {
		List<Teacher> teachers = getInstructors();
		Set<TeachingSwitch> switches = this.getTeachingSwitchs();
		Set<TeachingInterruption> interupts = this.getTeachingInterruptions();
		for (Teacher each : teachers) {
			if (each.equals(teacher)) {
				return true;
			}
			else {
				for (TeachingSwitch eachSwitch : switches) {
					if (DateUtil.isBetween(eachSwitch.getFromDate(), fromDate, toDate) &&
							eachSwitch.getInplaceTeacher().equals(teacher))
						return true;
				}
				for (TeachingInterruption eachInterupt : interupts) {
					if (DateUtil.isBetween(eachInterupt.getFromDate(), fromDate, toDate) &&
							eachInterupt.getSubstituteTeacher() != null && 
							eachInterupt.getSubstituteTeacher().equals(teacher))
						return true;
				}
			}
		}
		return false;
	}

	/**
	 * Ok
	 * count the number of students based on student's type
	 * @param type
	 * @return
	 */
	public int getNumberOfStudents(StudentType type) {
		int acc = 0;
		for (OfferingMember member : this.getMembers()) {
			if (member.getReceipt().getStudent().getType().equals(type)) {
				acc++;
			}
		}
		return acc;
	}

	/**
	 * Ok
	 * count the number of observers in the class
	 * @return
	 */
	public int getNumberOfObservers() {
		int acc = 0;
		for (OfferingMember member : this.getMembers()) {
			if (member.isObservable()) {
				acc++;
			}
		}
		return acc;
	}

	/**
	 * Ok
	 * check whether the class has finished yet
	 * @param from
	 * @param to
	 * @return
	 */
	public boolean isFinished(Date from, Date to) {
		return DateUtil.sequence(from, to).contains(this.endDate);
	}

	/**
	 * Ok
	 * check whether the class has started yet
	 * @param from
	 * @param to
	 * @return
	 */
	public boolean isStarted(Date from, Date to) {
		return DateUtil.sequence(from, to).contains(this.startDate);
	}

	/**
	 * Ok
	 * check whether the class contains the student or not
	 * @param student
	 * @return
	 */
	public boolean contains(Student student) {
		for (OfferingMember member : this.getMembers()) {
			if (member.getReceipt().getStudent() == student) {
				return true;
			}
		}
		return false;
	}

	/**
	 * Ok - halnt
	 * count the number of absent student from final Test base on FINAL SCORE
	 * if FINAL SCORE cannot be calculated then the student is consider absence from final test
	 * @param date
	 * @return
	 */
	public int getNumberOfAbsentMembers() {
		int count = 0;
		for (OfferingMember member : this.getMembers()) {
			if (member.isActive() && member.getTotalScore() == null) {
				count++;
				member.getId();
			}
		}
		return count;
	}

	/**
	 * Ok - halnt
	 * count the number of absent student at a specific date
	 * @param date
	 * @return
	 */
	public int getNumberOfFinalTestAbsentMembers() {
		int count = 0;
		for (OfferingMember member : this.getMembers()) {
			Attendance sAttendance = member.getAttendance(finalSpokenDate);
			Attendance wAttendance = member.getAttendance(finalWrittenDate);			
			if (member.isActive() && 
					((sAttendance != null && sAttendance.getStatus().equals(AttendanceStatus.ABSENT)) ||
					 (wAttendance != null && wAttendance.getStatus().equals(AttendanceStatus.ABSENT)))) {
					count++;
			}
		}
		return count;
	}

	/**
	 * Ok - halnt
	 * get the absent students from final test
	 * @param date
	 * @return
	 */
	public List<OfferingMember> getFinalTestAbsentMembers() {
		List<OfferingMember> result = new ArrayList<OfferingMember>();
		for (OfferingMember member : this.getMembers()) {
			Attendance sAttendance = member.getAttendance(finalSpokenDate);
			Attendance wAttendance = member.getAttendance(finalWrittenDate);			
			if (member.isActive() && 
					((sAttendance != null && sAttendance.getStatus().equals(AttendanceStatus.ABSENT)) ||
					 (wAttendance != null && wAttendance.getStatus().equals(AttendanceStatus.ABSENT)))) {
					result.add(member);
			}
		}
		return result;
	}

	/**
	 * Ok
	 * count the number of absent student at a specific date
	 * @param date
	 * @return
	 */
	public int getNumberOfAbsentMembers(Date date) {
		int count = 0;
		for (OfferingMember member : this.getMembers()) {
			Attendance attendance = member.getAttendance(date);
			if (attendance != null) {
				if (AttendanceStatus.ABSENT.equals(attendance.getStatus())) {
					count++;
				}
			}
		}
		return count;
	}

	/**
	 * Ok
	 * @param teacher
	 * @return
	 */
	public Collection<OfferingChecking> getOfferingCheckings(Teacher teacher) {
		Set<OfferingChecking> offeringCheckings = new LinkedHashSet<OfferingChecking>();
		for (OfferingChecking offeringChecking : this.offeringCheckings) {
			if (teacher == offeringChecking.getTeacher()) {
				offeringCheckings.add(offeringChecking);
			}
		}
		return offeringCheckings;
	}
	
	/**
	 * Ok
	 * get all instructor interruptions
	 * @return
	 */
	public List<TeachingInterruption> getInstructorInterruptions() {
		List<TeachingInterruption> ret = new ArrayList<TeachingInterruption>();
		for (TeachingInterruption each : this.teachingInterruptions) {
			if (each.getTeacher().isInstructor()) {
				ret.add(each);
			}
		}
		return ret;
	}
	
	/**
	 * Ok
	 * get all TA interruptions
	 * @return
	 */
	public List<TeachingInterruption> getTAInterruptions() {
		List<TeachingInterruption> ret = new ArrayList<TeachingInterruption>();
		for (TeachingInterruption each : this.teachingInterruptions) {
			if (each.getTeacher().isTA()) {
				ret.add(each);
			}
		}
		return ret;
	}
	
	/**
	 * get initial instructors of the class
	 * @return
	 */
	public List<Teacher> getInstructors() {
		Set<Entry<Integer, Teacher>> teachers = this.getDayInstructorMap().entrySet();
		return getTeachersHelp(teachers);
	}
	
	/**
	 * get real instructor of the class from a specific date
	 * @param fromDate
	 * @return
	 */
	public List<Teacher> getInstructors(Date fromDate) {
		Set<Entry<Integer, Teacher>> teachers = this.getDayInstructorMapFromDate(fromDate).entrySet();
		return getTeachersHelp(teachers);
	}
	
	/**
	 * get initial TAs of the class
	 * @return
	 */
	public List<Teacher> getTAs() {
		Set<Entry<Integer, Teacher>> tas = this.getDayTAMap().entrySet();
		return getTeachersHelp(tas);
	}
	
	/**
	 * @param fromDate
	 * @return
	 */
	public List<Teacher> getTAs(Date fromDate) {
		Set<Entry<Integer, Teacher>> tas = this.getDayTAMapFromDate(fromDate).entrySet();
		return getTeachersHelp(tas);
	}
	
	/**
	 * return list of teacher (instructor or TA) from the entry set
	 * @param entrySet
	 * @return
	 */
	private List<Teacher> getTeachersHelp(Set<Entry<Integer, Teacher>> entrySet) {
		List<Teacher> ret = new ArrayList<Teacher>();
		
		Iterator<Entry<Integer, Teacher>> iterator = entrySet.iterator();
		while(iterator.hasNext()) {
			Entry<Integer, Teacher> entry = iterator.next();
			ret.add(entry.getValue());
		}
		return ret;
	}

	/**
	 * Ok
	 * check whether the teacher has taught this class or not
	 * @param teacher
	 * @return
	 */
	public boolean containsInstructor(Teacher teacher) {
		List<Teacher> teachers = getInstructors();
		for (Teacher each : teachers) {
			if (each.equals(teacher)) {
				return true;
			}
		}
		return false;
	}
	
	/**
	 * Ok
	 * check whether the TA has taught this class or not
	 * @param ta
	 * @return
	 */
	public boolean containsTA(Teacher ta) {
		List<Teacher> tas = getTAs();
		for (Teacher each : tas) {
			if (each.equals(ta)) {
				return true;
			}
		}
		return false;
	}
	
	/**
	 * TODO
	 * @return
	 */
	public Set<Integer> getDays() {
		return new HashSet<Integer>(this.getDayInstructorMap().keySet());
	}
	
	/**
	 * Ok
	 * get teachers who really teach this class from specific date
	 * @param fromDate
	 * @return
	 */
	public List<Teacher> getRealInstructors(Date fromDate) {
		List<Teacher> teachers = this.getInstructors(fromDate);
		List<TeachingInterruption> instructorInterruptions = this.getInstructorInterruptions();
		for (TeachingInterruption each : instructorInterruptions) {
			if (TeachingInterruptionReason.SUBSTITUTE.equals(each.getReason())
					&& this.endDate.equals(each.getToDate())) {
				teachers.add(each.getSubstituteTeacher());
				teachers.remove(each.getTeacher());
			}
		}
		return teachers;
	}
	
	/**
	 * Ok
	 * get TA who really tutor this class from specific date
	 * @param fromDate
	 * @return
	 */
	public List<Teacher> getRealTAs(Date fromDate) {
		List<Teacher> teachers = this.getTAs(fromDate);
		List<TeachingInterruption> taInterruptions = this.getTAInterruptions();
		for (TeachingInterruption each : taInterruptions) {
			if (TeachingInterruptionReason.SUBSTITUTE.equals(each.getReason())
					&& this.endDate.equals(each.getToDate())) {
				teachers.add(each.getSubstituteTeacher());
				teachers.remove(each.getTeacher());
			}
		}
		return teachers;
	}
	
	/**
	 * TODO
	 * get the teacher who taught this class on a specific date
	 * @param date
	 * @return
	 */
	public Teacher getTeacher(Date date) {
		List<TeachingInterruption> makeUps = this.getInstructorMakeups(date);
		for(TeachingInterruption each : makeUps) {
			if(TeachingInterruptionReason.CANCEL.equals(each.getReason())) {
				return each.getTeacher();
			}
		}
		List<TeachingInterruption> interruptions = this.getInstructorInterruptions(date);
		for (TeachingInterruption each : interruptions) {
			if (!TeachingInterruptionReason.SUBSTITUTE.equals(each.getReason())) {
				return each.getTeacher();
			}
		}
		List<TeachingInterruption> tmp = this.getInstructorInterruptions(date);
		Teacher acc = this.getInstructorOfDay(DateUtil.getDayOfWeek(date), date);
		return this.getTeacherHelp(tmp, acc);
	}

	/**
	 * get the TA who tutor this class on a specific date
	 * @param date
	 * @return
	 */
	public Teacher getTA(Date date) {
		List<TeachingInterruption> makeUps = this.getTAMakeups(date);
		for(TeachingInterruption each : makeUps) {
			if(TeachingInterruptionReason.CANCEL.equals(each.getReason())) {
				return each.getTeacher();
			}
		}
		List<TeachingInterruption> interruptions = this.getTAInterruptions(date);
		for (TeachingInterruption each : interruptions) {
			if (!TeachingInterruptionReason.SUBSTITUTE.equals(each.getReason())) {
				return each.getTeacher();
			}
		}
		List<TeachingInterruption> tmp = this.getTAInterruptions(date);
		Teacher acc = this.getTAOfDay(DateUtil.getDayOfWeek(date), date);
		return this.getTeacherHelp(tmp, acc);
	}
	
	/**
	 * TODO
	 * get the teacher who taught this class from another teacher
	 * @param interruptions
	 * @param teacher
	 * @return
	 */
	private Teacher getTeacherHelp(List<TeachingInterruption> interruptions, Teacher teacher) {
		TeachingInterruption tmp = null;
		for (int i = 0; i < interruptions.size(); i++) {
			if (TeachingInterruptionReason.SUBSTITUTE.equals(interruptions.get(i).getReason())) {
				if (interruptions.get(i).getTeacher() == teacher) {
					tmp = interruptions.remove(i);
					return this.getTeacherHelp(interruptions, tmp.getSubstituteTeacher());
				}
			}
		}
		return teacher;
	}
	
	/**
	 * get set of days that the teacher is original assigned
	 * @param teacher
	 * @return
	 */
	@Deprecated
	public Set<Integer> getInitialDaysOfTeacher(Teacher teacher) {
		Set<Integer> days = new HashSet<Integer>();
		if(this.getInstructors().contains(teacher)) {
			for(Entry<Integer, Teacher> entry : this.getDayInstructorMap().entrySet()) {
				if(entry.getValue().equals(teacher)) {
					days.add(entry.getKey());
				}
			}
		}
		return days;
	}
	
	/**
	 * Get the first day that the teacher'll teach this class
	 * @param teacher
	 * @return
	 */
	@Deprecated
	public Date getInitialFirstDayOfTeacher(Teacher teacher) {
		Set<Integer> days = this.getInitialDaysOfTeacher(teacher);
		for(Date date : DateUtil.sequenceAsList(this.startDate, this.endDate)) {
			if(days.contains(DateUtil.getDayOfWeek(date))) {
				return date;
			}
		}
		return null;
	}
	
	/**
	 * TODO
	 * @param date
	 * @return
	 */
	private List<TeachingInterruption> getInstructorMakeups(Date date) {
		List<TeachingInterruption> makeUps = new ArrayList<TeachingInterruption>();
		List<TeachingInterruption> instructorInterruptions = this.getInstructorInterruptions();
		for(TeachingInterruption each : instructorInterruptions) {
			if(each.containMakeUps(date)) {
				makeUps.add(each);
			}
		}
		return makeUps;
	}
	
	/**
	 * TODO
	 * @param date
	 * @return
	 */
	public TeachingInterruption getInstructorMakeUp(Date date) {
		List<TeachingInterruption> interruptions = this.getInstructorMakeups(date);
		for(TeachingInterruption makeUp : interruptions) {
			if(makeUp.containMakeUps(date)) {
				return  makeUp;
			}
		}
		return null;
	}
	
	/**
	 * TODO
	 * @param date
	 * @return
	 */
	private List<TeachingInterruption> getTAMakeups(Date date) {
		List<TeachingInterruption> makeUps = new ArrayList<TeachingInterruption>();
		List<TeachingInterruption> taInterruptions = this.getTAInterruptions();
		for(TeachingInterruption each : taInterruptions) {
			if(each.containMakeUps(date)) {
				makeUps.add(each);
			}
		}
		return makeUps;
	}
	
	public TeachingInterruption getTAMakeUp(Date date) {
		List<TeachingInterruption> interruptions = this.getTAMakeups(date);
		for(TeachingInterruption makeUp : interruptions) {
			if(makeUp.containMakeUps(date)) {
				return  makeUp;
			}
		}
		return null;
	}

	/**
	 * @param date
	 * @return
	 */
	private List<TeachingInterruption> getInstructorInterruptions(Date date) {
		List<TeachingInterruption> interruptions = this.getInstructorInterruptions();
		return getInterruptionsHelp(date, interruptions);
	}
	
	private List<TeachingInterruption> getTAInterruptions(Date date) {
		List<TeachingInterruption> interruptions = this.getTAInterruptions();
		return getInterruptionsHelp(date, interruptions);
	}
	
	private List<TeachingInterruption> getInterruptionsHelp(Date date, List<TeachingInterruption> interruptions) {
		List<TeachingInterruption> ret = new ArrayList<TeachingInterruption>();
		for (TeachingInterruption each : interruptions) {
			if (each.contains(date)) {
				ret.add(each);
			}
		}
		return ret;
	}

	/**
	 * @param date
	 * @return
	 */
	public TeachingInterruption getInstructorInterruption(Date date) {
		Teacher mainTeacher = this.getInstructorOfDay(DateUtil.getDayOfWeek(date), date);
		if (mainTeacher == null)
			return null;
		List<TeachingInterruption> interruptions = this.getInstructorInterruptions(date);
		for (TeachingInterruption each : interruptions) {
			if (!TeachingInterruptionReason.SUBSTITUTE.equals(each.getReason())) {
				return each;
			}
		}
		return this.getInterruptionHelp(interruptions, mainTeacher.getId(), null);
	}
	
	public TeachingInterruption getTAInterruption(Date date) {
		Teacher mainTeacher = this.getTAOfDay(DateUtil.getDayOfWeek(date), date);
		if (mainTeacher == null)
			return null;
		List<TeachingInterruption> interruptions = this.getTAInterruptions(date);
		for (TeachingInterruption each : interruptions) {
			if (!TeachingInterruptionReason.SUBSTITUTE.equals(each.getReason())) {
				return each;
			}
		}
		return this.getInterruptionHelp(interruptions, mainTeacher.getId(), null);
	}

	private TeachingInterruption getInterruptionHelp(List<TeachingInterruption> interruptions, long teacherId, TeachingInterruption acc) {
		TeachingInterruption tmp = null;
		for (int i = 0; i < interruptions.size(); i++) {
			if (TeachingInterruptionReason.SUBSTITUTE.equals(interruptions.get(i).getReason())) {
				if (interruptions.get(i).getTeacher().getId() == teacherId) {
					tmp = interruptions.remove(i);
					return getInterruptionHelp(interruptions, tmp.getSubstituteTeacher().getId(), tmp);
				}
			}
		}
		return acc;
	}

	/**
	 * get the instructor's interruptions by the reason
	 * @param reasonName
	 * @return
	 */
	public Collection<TeachingInterruption> getInstructorInterruptions(String reasonName) {
		List<TeachingInterruption> interruptions = this.getInstructorInterruptions();
		return getTeacherInterruptionsHelp(reasonName, interruptions);
	}

	public Collection<TeachingInterruption> getTAInterruptions(String reasonName) {
		List<TeachingInterruption> interruptions = this.getTAInterruptions();
		return getTeacherInterruptionsHelp(reasonName, interruptions);
	}
	
	private List<TeachingInterruption> getTeacherInterruptionsHelp(String reasonName, List<TeachingInterruption> interruptions) {
		TeachingInterruptionReason reason = TeachingInterruptionReason.create(reasonName);
		List<TeachingInterruption> result = new ArrayList<TeachingInterruption>();
		for (TeachingInterruption each : interruptions) {
			if (each.getReason().equals(reason)) {
				result.add(each);
			}
		}
		Comparator<TeachingInterruption> comp = new Comparator<TeachingInterruption>() {
			@Override
			public int compare(TeachingInterruption interruption1, TeachingInterruption interruption2) {
				return interruption2.getFromDate().compareTo(interruption1.getFromDate());
			}
		};
		Collections.sort(result, comp);
		return result;
	}
	
	/**
	 * produce a map that the key is the day of week and the value is the teacher 
	 * who is assigned to teach this class
	 * @return
	 */
	private Map<Integer, Teacher> getDayInstructorMap() {
		Map<Integer, Teacher> map = new LinkedHashMap<Integer, Teacher>();
		if (this.monTeacher != null)
			map.put(Calendar.MONDAY, this.monTeacher);
		if (this.tueTeacher != null)
			map.put(Calendar.TUESDAY, this.tueTeacher);
		if (this.wedTeacher != null)
			map.put(Calendar.WEDNESDAY, this.wedTeacher);
		if (this.thuTeacher != null)
			map.put(Calendar.THURSDAY, this.thuTeacher);
		if (this.friTeacher != null)
			map.put(Calendar.FRIDAY, this.friTeacher);
		if (this.satTeacher != null)
			map.put(Calendar.SATURDAY, this.satTeacher);
		if (this.sunTeacher != null)
			map.put(Calendar.SUNDAY, this.sunTeacher);
		return map;
	}
	
	/**
	 * produce a map that the key is the day of week and the value is the teacher
	 * who is assigned to teach this class (include switch case)
	 * @param date
	 * @return
	 */
	public Map<Integer, Teacher> getDayInstructorMap(Date date) {
		int day = DateUtil.getDayOfWeek(date);
		Map<Integer, Teacher> map = getDayInstructorMap();
		for(TeachingSwitch each : this.teachingSwitchs) {
			if(each.getMainDay() == day && each.contains(date)) {
				Teacher initialTeacher = this.getInstructorOfDay(day, null);
				if(initialTeacher.equals(each.getMainTeacher())) {
					map.put(day, each.getInplaceTeacher());
				}
			}
		}
		return map;
	}
	
	/**
	 * @param fromDate
	 * @return
	 */
	public Map<Integer, Teacher> getDayInstructorMapFromDate(Date fromDate) {
		Map<Integer, Teacher> map = getDayInstructorMap();
		for(TeachingSwitch each : this.teachingSwitchs) {
			if(each.contains(fromDate)) {
				Teacher initialTeacher = this.getInstructorOfDay(each.getMainDay(), null);
				if(initialTeacher.equals(each.getMainTeacher())) {
					map.put(each.getMainDay(), each.getInplaceTeacher());
				}
			}
		}
		return map;
	}
	
	/**
	 * get the teacher who'll teach this class at a specific day and from specific date
	 * 
	 * @param day
	 * @param date
	 * @return
	 */
	public Teacher getInstructorOfDay(Integer day, Date date) {
		Teacher ret = null;
		if(date != null) {
			ret = this.getDayInstructorMap(date).get(day);
		} else {
			ret = this.getDayInstructorMap().get(day); 
		}
		return ret;
	}
	
	/**
	 * produce a map that the key is the day of week and the value is the TA 
	 * who is assigned to tutor this class
	 * @return
	 */
	private Map<Integer, Teacher> getDayTAMap() {
		Map<Integer, Teacher> map = new LinkedHashMap<Integer, Teacher>();
		if (Checker.isNotNull(this.monTATeacher))
			map.put(Calendar.MONDAY, this.monTATeacher);
		if (Checker.isNotNull(this.tueTATeacher))
			map.put(Calendar.TUESDAY, this.tueTATeacher);
		if (Checker.isNotNull(this.wedTATeacher))
			map.put(Calendar.WEDNESDAY, this.wedTATeacher);
		if (Checker.isNotNull(this.thuTATeacher))
			map.put(Calendar.THURSDAY, this.thuTATeacher);
		if (Checker.isNotNull(this.friTATeacher))
			map.put(Calendar.FRIDAY, this.friTATeacher);
		if (Checker.isNotNull(this.satTATeacher))
			map.put(Calendar.SATURDAY, this.satTATeacher);
		if (Checker.isNotNull(this.sunTATeacher))
			map.put(Calendar.SUNDAY, this.sunTATeacher);
		return map;
	}
	
	/**
	 * not in use right now (in case TA Switch occurs)
	 * 
	 * @param date
	 * @return
	 */
	public Map<Integer, Teacher> getDayTAMap(Date date) {
		Map<Integer, Teacher> map = this.getDayTAMap();
		return map;
	}
	
	/**
	 * not in use right now (in case TA Switch occurs)
	 * 
	 * @param fromDate
	 * @return
	 */
	public Map<Integer, Teacher> getDayTAMapFromDate(Date fromDate) {
		Map<Integer, Teacher> map = this.getDayTAMap();
		return map;
	}
	
	/**
	 * get the teaching assistant who'll tutor this class at a specific day and from specific date
	 * 
	 * @param day
	 * @param date
	 * @return
	 */
	public Teacher getTAOfDay(Integer day, Date date) {
		Teacher ret = null;
		if(date != null) {
			ret = this.getDayTAMap(date).get(day);
		} else {
			ret = this.getDayTAMap().get(day); 
		}
		return ret;
	}
	
	/**
	 * Ok
	 * get the list of make-up tests
	 */
	public List<FinalTest> getMakeUpTests() {
		List<FinalTest> ret = new ArrayList<FinalTest>();
		Set<AbstractReceipt> receipts = this.getOfferingReceipts();
		for (AbstractReceipt receipt : receipts) {
			FinalTest finalTest = receipt.getOfferingMember().getFinalTest();
			if (finalTest.checkIsMakeUp())
				ret.add(finalTest);
		}
		return ret;
	}

	/**
	 * Ok
	 * get the list of second final tests
	 * @return
	 */
	public List<SecondTest> getSecondFinalTests() {
		List<SecondTest> ret = new ArrayList<SecondTest>();
		Set<AbstractReceipt> receipts = this.getOfferingReceipts();
		for (AbstractReceipt receipt : receipts) {
			SecondTest secondTest = receipt.getOfferingMember().getSecondFinalTest();
			if (secondTest != null) {
				ret.add(secondTest);
			}
		}
		return ret;
	}
	
	/**
	 * Ok
	 * check whether this class has studied in a specific date
	 * @param date
	 * @return
	 */
	public boolean checkExistStudy(Date date) {
		boolean ret = false;
		if(DateUtil.sequenceAsList(startDate, endDate).contains(date)) {
			int day = DateUtil.getDayOfWeek(date);
			ret = this.getDays().contains(day);
		}
		return ret;
	}
	
	/**
	 * Ok
	 * check whether this class has studied in a specific date and shift
	 * @param date
	 * @return
	 */
	public boolean checkExistStudyShift(Date date, Shift shift, Room room) {
		boolean ret = false;
		if(shift.equals(this.getShift()) && room.equals(this.getRoom())) {
			if(DateUtil.sequenceAsList(startDate, endDate).contains(date)) {
				int day = DateUtil.getDayOfWeek(date);
				ret = this.getDays().contains(day);
			}
		}
		return ret;
	}
	
	/**
	 * Ok
	 * check whether this class has any exam / video show or not on a specific date
	 * @param date
	 * @return
	 */
	public boolean checkExistStudyingSchedule(Date date) {
		return checkExistVideoSchedule(date) || checkExistTestSchedule(date);
	}
	
	/**
	 * Halnt
	 * check whether this class has any video show or not on a specific date
	 * @param date
	 * @return
	 */
	public boolean checkExistVideoScheduleNTest(Date date) {
		return checkExistVideoSchedule(date) || checkExistTest(date);
	}

	/**
	 * Ok
	 * check whether this class has any video show or not on a specific date
	 * @param date
	 * @return
	 */
	public boolean checkExistVideoSchedule(Date date) {
		Set<VideoSchedule> videos = this.getVideoSchedules();
		for (VideoSchedule video : videos) {
			if (video.getDate().equals(date)) {
				return true;
			}
		}
		return false;
	}

	/**
	 * Ok
	 * check whether this class has any exam or not on a specific date
	 * @param date
	 * @return
	 */
	public boolean checkExistTestSchedule(Date date) {
		Set<TestSchedule> tests = this.getTestSchedules();
		for (TestSchedule test : tests) {
			if (test.getDate().equals(date)) {
				return true;
			}
		}
		return false;
	}

	/**
	 * Ok
	 * check whether this class has any exam or not on a specific date
	 * @param date
	 * @return
	 */
	public boolean checkExistTest(Date date) {
		if ((this.midtermWrittenDate != null && this.midtermWrittenDate.equals(date)) ||
			(this.finalSpokenDate != null && this.finalSpokenDate.equals(date)) ||
			(this.finalWrittenDate != null && this.finalWrittenDate.equals(date)) ||
			(this.cambridgeSpokenDate != null && this.cambridgeSpokenDate.equals(date)) ||
			(this.cambridgeWrittenDate != null && this.cambridgeWrittenDate.equals(date))) {
				return true;
		}
		return false;
	}

	/**
	 * TODO
	 * @param date
	 * @return
	 */
	public VideoSchedule getVideoSchedule(Date date) {
		Iterator<VideoSchedule> iterator = this.getVideoSchedules().iterator();
		boolean found = false;
		while (iterator.hasNext() && !found) {
			VideoSchedule video = iterator.next();
			if (video.getDate().equals(date)) {
				return video;
			}
		}
		return null;
	}

	/**
	 * TODO
	 * @param date
	 * @return
	 */
	public TestSchedule getTestSchedule(Date date) {
		Iterator<TestSchedule> iterator = this.getTestSchedules().iterator();
		boolean found = false;
		while (iterator.hasNext() && !found) {
			TestSchedule test = iterator.next();
			if (test.getDate().equals(date)) {
				return test;
			}
		}
		return null;
	}

	/**
	 * TODO
	 * @param date
	 * @return
	 */
	public String getTest(Date date) {		
		if ((this.midtermWrittenDate != null && this.midtermWrittenDate.equals(date)))
			return "Midterm Written";
		else if ((this.finalSpokenDate != null && this.finalSpokenDate.equals(date)))
			return "Final Oral";
		else if ((this.finalWrittenDate != null && this.finalWrittenDate.equals(date)))
			return "Final Written";
		else if ((this.cambridgeSpokenDate != null && this.cambridgeSpokenDate.equals(date)))
			return "Cambridge Oral";
		else if ((this.cambridgeWrittenDate != null && this.cambridgeWrittenDate.equals(date)))
			return "Cambridge Written";
		return null;
	}
	
	/**
	 * TODO
	 * @param absence
	 */
	public void addAbsence(AbsenceRecord absence) {
		this.absences.add(absence);
	}

	// Getter & Setter
	public Level getLevel() {
		return level;
	}

	public void setLevel(Level level) {
		this.level = level;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Set<EvaluateTeacher> getEvaluateTeachers() {
		return evaluateTeachers;
	}

	public void setEvaluateTeachers(Set<EvaluateTeacher> evaluateTeachers) {
		this.evaluateTeachers = evaluateTeachers;
	}

	public Room getRoom() {
		return room;
	}

	public void setRoom(Room room) {
		this.room = room;
	}

	public String getComment() {
		return comment;
	}

	public void setComment(String comment) {
		this.comment = comment;
	}

	public Date getEndDate() {
		return endDate;
	}

	public void setEndDate(Date endDate) {
		this.endDate = endDate;
	}

	public Teacher getFriTeacher() {
		return friTeacher;
	}

	public void setFriTeacher(Teacher friTeacher) {
		this.friTeacher = friTeacher;
	}

	public Teacher getMonTeacher() {
		return monTeacher;
	}

	public void setMonTeacher(Teacher monTeacher) {
		this.monTeacher = monTeacher;
	}

	public Teacher getSatTeacher() {
		return satTeacher;
	}

	public void setSatTeacher(Teacher satTeacher) {
		this.satTeacher = satTeacher;
	}

	public Date getStartDate() {
		return startDate;
	}

	public void setStartDate(Date startDate) {
		this.startDate = startDate;
	}

	public Teacher getSunTeacher() {
		return sunTeacher;
	}

	public void setSunTeacher(Teacher sunTeacher) {
		this.sunTeacher = sunTeacher;
	}

	public Date getMidtermWrittenDate() {
		return midtermWrittenDate;
	}

	public void setMidtermWrittenDate(Date midtermWrittenDate) {
		this.midtermWrittenDate = midtermWrittenDate;
	}

	public Date getFinalSpokenDate() {
		return finalSpokenDate;
	}

	public void setFinalSpokenDate(Date finalSpokenDate) {
		this.finalSpokenDate = finalSpokenDate;
	}

	public Date getFinalWrittenDate() {
		return finalWrittenDate;
	}

	public void setFinalWrittenDate(Date finalWrittenDate) {
		this.finalWrittenDate = finalWrittenDate;
	}

	public Teacher getThuTeacher() {
		return thuTeacher;
	}

	public void setThuTeacher(Teacher thuTeacher) {
		this.thuTeacher = thuTeacher;
	}

	public Shift getShift() {
		return shift;
	}

	public void setShift(Shift shift) {
		this.shift = shift;
	}

	public Teacher getTueTeacher() {
		return tueTeacher;
	}

	public void setTueTeacher(Teacher tueTeacher) {
		this.tueTeacher = tueTeacher;
	}

	public Teacher getWedTeacher() {
		return wedTeacher;
	}

	public void setWedTeacher(Teacher wedTeacher) {
		this.wedTeacher = wedTeacher;
	}

	public Set<AbstractReceipt> getOfferingReceipts() {
		return offeringReceipts;
	}

	public void setOfferingReceipts(Set<AbstractReceipt> offeringReceipts) {
		this.offeringReceipts = offeringReceipts;
	}

	public Set<OfferingChecking> getOfferingCheckings() {
		return offeringCheckings;
	}

	public void setOfferingCheckings(Set<OfferingChecking> offeringCheckings) {
		this.offeringCheckings = offeringCheckings;
	}

	public Date getIssueDate() {
		return issueDate;
	}

	public void setIssueDate(Date issueDate) {
		this.issueDate = issueDate;
	}

	public Set<TeachingInterruption> getTeachingInterruptions() {
		return teachingInterruptions;
	}

	public void setTeachingInterruptions(
			Set<TeachingInterruption> teachingInterruptions) {
		this.teachingInterruptions = teachingInterruptions;
	}
	
	public Set<TeachingSwitch> getTeachingSwitchs() {
		return teachingSwitchs;
	}

	public void setTeachingSwitchs(Set<TeachingSwitch> teachingSwitchs) {
		this.teachingSwitchs = teachingSwitchs;
	}

	public Set<Opinion> getOpinions() {
		return opinions;
	}

	public void setOpinions(Set<Opinion> opinions) {
		this.opinions = opinions;
	}

	public Set<Suggestion> getSuggestions() {
		return suggestions;
	}

	public void setSuggestions(Set<Suggestion> suggestions) {
		this.suggestions = suggestions;
	}

	public Set<VideoSchedule> getVideoSchedules() {
		return videoSchedules;
	}

	public void setVideoSchedules(Set<VideoSchedule> videoSchedules) {
		this.videoSchedules = videoSchedules;
	}

	public Set<TestSchedule> getTestSchedules() {
		return testSchedules;
	}

	public void setTestSchedules(Set<TestSchedule> testSchedules) {
		this.testSchedules = testSchedules;
	}

	public Set<AbsenceRecord> getAbsences() {
		return absences;
	}

	public void setAbsences(Set<AbsenceRecord> absences) {
		this.absences = absences;
	}

	public Teacher getMonTATeacher() {
		return monTATeacher;
	}

	public void setMonTATeacher(Teacher monTATeacher) {
		this.monTATeacher = monTATeacher;
	}

	public Teacher getTueTATeacher() {
		return tueTATeacher;
	}

	public void setTueTATeacher(Teacher tueTATeacher) {
		this.tueTATeacher = tueTATeacher;
	}

	public Teacher getWedTATeacher() {
		return wedTATeacher;
	}

	public void setWedTATeacher(Teacher wedTATeacher) {
		this.wedTATeacher = wedTATeacher;
	}

	public Teacher getThuTATeacher() {
		return thuTATeacher;
	}

	public void setThuTATeacher(Teacher thuTATeacher) {
		this.thuTATeacher = thuTATeacher;
	}

	public Teacher getFriTATeacher() {
		return friTATeacher;
	}

	public void setFriTATeacher(Teacher friTATeacher) {
		this.friTATeacher = friTATeacher;
	}

	public Teacher getSatTATeacher() {
		return satTATeacher;
	}

	public void setSatTATeacher(Teacher satTATeacher) {
		this.satTATeacher = satTATeacher;
	}

	public Teacher getSunTATeacher() {
		return sunTATeacher;
	}

	public void setSunTATeacher(Teacher sunTATeacher) {
		this.sunTATeacher = sunTATeacher;
	}

	public Date getCambridgeSpokenDate() {
		return cambridgeSpokenDate;
	}

	public void setCambridgeSpokenDate(Date cambridgeSpokenDate) {
		this.cambridgeSpokenDate = cambridgeSpokenDate;
	}

	public Date getCambridgeWrittenDate() {
		return cambridgeWrittenDate;
	}

	public void setCambridgeWrittenDate(Date cambridgeWrittenDate) {
		this.cambridgeWrittenDate = cambridgeWrittenDate;
	}

	public GradeDetail getMidtermGradeDetail() {
		return midtermGradeDetail;
	}

	public void setMidtermGradeDetail(GradeDetail midtermGradeDetail) {
		this.midtermGradeDetail = midtermGradeDetail;
	}

	public GradeDetail getFinalGradeDetail() {
		return finalGradeDetail;
	}

	public void setFinalGradeDetail(GradeDetail finalGradeDetail) {
		this.finalGradeDetail = finalGradeDetail;
	}

	public GradeDetail getCambridgeGradeDetail() {
		return cambridgeGradeDetail;
	}

	public void setCambridgeGradeDetail(GradeDetail cambridgeGradeDetail) {
		this.cambridgeGradeDetail = cambridgeGradeDetail;
	}

	public NextOffering getNextOffering() {
		return nextOffering;
	}

	public void setNextOffering(NextOffering nextOffering) {
		this.nextOffering = nextOffering;
	}

	public Set<ClassSituation> getClassSituations() {
		return classSituations;
	}

	public void setClassSituations(Set<ClassSituation> classSituations) {
		this.classSituations = classSituations;
	}

	public boolean isCancel() {
		return cancel;
	}

	public void setCancel(boolean cancel) {
		this.cancel = cancel;
	}
	
	@Override
	public boolean equals(Object that) {		
		return this.getId().equals(((Offering)that).getId());
	}
}